using System;
using System.Text.RegularExpressions;
using Fadd.Globalization;
#if TEST
using Xunit;
#endif

namespace Fadd.Validation
{
    /// <summary>
    /// Let's you validate a string field using regular expressions.
    /// </summary>
    public class ValidateRegularExpression : ValidateAttribute
    {
        private readonly string _value;
        private readonly string _languageName;

        /// <summary>
        /// Initializes a new instance of the <see cref="ValidateRegularExpression"/> class.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="languageName">Name in language text to use, or a error message.</param>
        /// <seealso cref="Format"/>
        /// <example>
        /// // will use the supplied text as error message if validation fails.
        /// [ValidateRegularExpression("^[a-zA-Z0-9_\.\-]+@[a-zA-Z0-9_\.\-]+\.[a-zA-Z]{2,4}$", "Incorrect email")] 
        /// public string Email{get;set;}
        /// 
        /// //will use the InvalidEmail text from the language file
        /// [ValidateRegularExpression("^[a-zA-Z0-9_\.\-]+@[a-zA-Z0-9_\.\-]+\.[a-zA-Z]{2,4}$", "InvalidEmail")] 
        /// public string Email{get;set;}
        /// </example>
        public ValidateRegularExpression(object value, string languageName)
        {
            _value = (string)value;
            _languageName = languageName;
        }

        /// <summary>
        /// Regular Expression
        /// </summary>
        public string Value
        {
            get { return _value; }
        }

        /// <summary>
        /// Validate value
        /// </summary>
        /// <param name="context">Can be used to send a context object to the validation class. Useful if you provide your own validation classes which need to get information from your application. <seealso cref="BeforeValidationEventArgs"/></param>
        /// <param name="value">value to validate</param>
        /// <returns>
        /// true if value passed the validation or if value is empty; otherwise false.
        /// </returns>
        public override bool Validate(object context, object value)
        {
            if (string.IsNullOrEmpty(value as string))
                return true;

            bool result  = Regex.IsMatch(value.ToString(), _value);

            return result;
        }

        /// <summary>
        /// Localize error if validation failed.
        /// </summary>
        /// <param name="fieldName">Localized field name.</param>
        /// <param name="validationLanguage">Language node with all validation translations.</param>
        /// <returns>A localized error message if the validation failed; otherwise null.</returns>
        /// <example>
        /// <code>
        /// attribute.Localize("FirstName", "'{0}' is required"); 
        /// // will return "'{0}' is required" if the validation failed, else null.
        /// </code>
        /// </example>
        public override string Format(string fieldName, ILanguageNode validationLanguage)
        {
            if (_languageName.Contains(" "))
                return _languageName;
            return validationLanguage == null ? _languageName : validationLanguage[_languageName];
        }

        /// <summary>
        /// Determines if the validation class support the specified type.
        /// </summary>
        /// <param name="type">Property/Value type.</param>
        /// <returns>true if the type is supported.</returns>
        public override bool SupportsType(Type type)
        {
            return type == typeof (string);
        }

#if TEST
        [Fact]
        private static void Test()
        {
            // email regex
            ValidateRegularExpression attribute = new ValidateRegularExpression(@"^[a-zA-Z0-9_\.\-]+@[a-zA-Z0-9_\.\-]+\.[a-zA-Z]{2,4}$", "MyError");
            Assert.True(attribute.Validate(null, @"rpm@yahoo.com"));
            Assert.True(attribute.Validate(null, @"rpm.text@yahoo.com"));
            Assert.False(attribute.Validate(null, @"rpm.yahoo.com"));
            
            //us postal code regex
            attribute = new ValidateRegularExpression(@"^(\d{5}-\d{4}|\d{5}|\d{9})$|^([a-zA-Z]\d[a-zA-Z] \d[a-zA-Z]\d)$", "Error");

            Assert.True(attribute.Validate(null, @"94107-8350"));
            Assert.True(attribute.Validate(null, @"941078350"));
            Assert.False(attribute.Validate(null, @"9410-78350"));
            Assert.False(attribute.Validate(null, @"9410783509"));

            
        }
#endif
    }
}
